package com.bfly.mall.wechat.common;

import com.alibaba.fastjson.JSONObject;
import com.bfly.common.json.JaxbUtil;
import com.bfly.common.json.JsonUtil;
import com.bfly.common.util.NetUtil;
import com.bfly.core.base.entity.RemoteResponse;
import com.bfly.core.cache.SysConfigCacheUtil;
import com.bfly.mall.system.dto.WXPayConfigDTO;
import com.bfly.mall.wechat.minipro.service.WeChatMiniProAPi;
import com.wechat.pay.contrib.apache.httpclient.WechatPayHttpClientBuilder;
import com.wechat.pay.contrib.apache.httpclient.util.PemUtil;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.Header;
import org.apache.http.HttpEntity;
import org.apache.http.HttpRequestInterceptor;
import org.apache.http.StatusLine;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpRequestBase;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.util.EntityUtils;

import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.security.KeyStore;
import java.security.PrivateKey;
import java.security.cert.X509Certificate;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;

/**
 * 正对微信Api请求封装的工具类
 *
 * @author 长沙商脉科技有限公司
 * @date 2020/12/11 18:31
 */
public class WeChatHttpUtil {

    // 微信支付v3 api httpClient
    private static CloseableHttpClient httpClientV3;

    // 微信支付v1 api httpsClient
    private static CloseableHttpClient httpsClientV1;

    /**
     * 微信支付v3 api 链接客户端
     *
     * @author 长沙商脉科技有限公司
     * @date 2020/12/11 18:44
     */
    public synchronized static CloseableHttpClient getWeChatPayHttpClientV3() {
        if (httpClientV3 == null) {
            WXPayConfigDTO wxPayConfig = SysConfigCacheUtil.getWxPayConfig();
            try (InputStream inputStream = new FileInputStream(new File(wxPayConfig.getCertPemPath()))) {
                X509Certificate certificate = PemUtil.loadCertificate(inputStream);
                PrivateKey privateKey = WeChatMiniProAPi.getPrivateKey(wxPayConfig.getKeyPemPath());
                WechatPayHttpClientBuilder builder = WechatPayHttpClientBuilder.create()
                        .withMerchant(wxPayConfig.getMchId(), wxPayConfig.getSerialNo(), privateKey)
                        .withWechatpay(Arrays.asList(certificate)).withValidator(res -> true);
                builder.addInterceptorFirst((HttpRequestInterceptor) (request, context) -> {
                    request.addHeader("User-Agent", "BFlyMallServer/1.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.198 Safari/537.36");
                    request.addHeader("Accept-Language", "zh-CN");
                    request.addHeader("Accept", "application/json");
                    request.addHeader("Content-Type", "application/json");
                });
                httpClientV3 = builder.build();
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }
        return httpClientV3;
    }

    /**
     * 微信支付V1 api Https
     *
     * @author 长沙商脉科技有限公司
     * @date 2020/12/11 19:09
     */
    public synchronized static CloseableHttpClient getWeChatPayHttpsClientV1() {
        if (httpsClientV1 == null) {
            WXPayConfigDTO wxPayConfig = SysConfigCacheUtil.getWxPayConfig();
            try (FileInputStream inputStream = new FileInputStream(wxPayConfig.getCertP12Path())) {
                KeyStore ks = KeyStore.getInstance("PKCS12");
                ks.load(inputStream, wxPayConfig.getMchId().toCharArray());

                SSLContext sslcontext = SSLContext.getInstance("TLS");
                KeyManagerFactory kf = KeyManagerFactory.getInstance("SunX509");
                kf.init(ks, wxPayConfig.getMchId().toCharArray());
                sslcontext.init(kf.getKeyManagers(), null, null);

                HttpClientBuilder builder = HttpClientBuilder.create();
                SSLConnectionSocketFactory factory = new SSLConnectionSocketFactory(sslcontext);

                builder.addInterceptorFirst((HttpRequestInterceptor) (request, context) -> {
                    request.addHeader("User-Agent", "BFlyMallServer/1.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.198 Safari/537.36");
                    request.addHeader("Accept-Language", "zh-CN");
                    request.addHeader("Content-Type", "text/xml; charset=UTF-8");
                });
                httpsClientV1 = builder.setSSLSocketFactory(factory).build();
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }
        return httpsClientV1;
    }

    /**
     * 微信支付v3 api请求封装
     *
     * @author 长沙商脉科技有限公司
     * @date 2020/12/11 18:36
     */
    public static RemoteResponse weChatPayHttpRequestV3(HttpRequestBase request) {
        RemoteResponse remoteResponse;
        CloseableHttpResponse response;
        CloseableHttpClient httpClient = getWeChatPayHttpClientV3();
        try {
            response = httpClient.execute(request);
            remoteResponse = new RemoteResponse();

            HttpEntity entity = response.getEntity();
            StatusLine statusLine = response.getStatusLine();

            //v3 api http状态就代表了业务状态
            remoteResponse.setCode(statusLine.getStatusCode());
            boolean isSuccess = statusLine.getStatusCode() >= 200 && statusLine.getStatusCode() <= 300;
            if (entity != null) {
                remoteResponse.setContentType(entity.getContentType().getName());
                remoteResponse.setContentLength(entity.getContentLength());

                String body = EntityUtils.toString(entity);
                remoteResponse.setBody(body);

                if (!isSuccess) {
                    JSONObject json = JsonUtil.parse(body, JSONObject.class);
                    remoteResponse.setErrorCode(json.getString("code"));
                    remoteResponse.setErrorMsg(json.getString("message"));
                }
            }
            remoteResponse.setSuccessful(isSuccess);
            remoteResponse.setMessage(response.getStatusLine().getReasonPhrase());
            getHeaders(remoteResponse, response);
        } catch (Exception e) {
            throw new RuntimeException(e);
        } finally {
            request.releaseConnection();
        }
        return remoteResponse;
    }

    /**
     * 微信支付v3 api请求封装
     *
     * @author 长沙商脉科技有限公司
     * @date 2020/12/11 18:36
     */
    public static RemoteResponse weChatPayHttpsRequestV1(HttpRequestBase request) {
        RemoteResponse remoteResponse;
        CloseableHttpResponse response;
        CloseableHttpClient httpClient = getWeChatPayHttpsClientV1();
        try {
            response = httpClient.execute(request);
            remoteResponse = new RemoteResponse();

            HttpEntity entity = response.getEntity();
            StatusLine statusLine = response.getStatusLine();

            remoteResponse.setCode(statusLine.getStatusCode());
            boolean isSuccess = true;
            if (entity != null) {
                remoteResponse.setContentType(entity.getContentType().getName());
                remoteResponse.setContentLength(entity.getContentLength());

                String body = EntityUtils.toString(entity, "UTF-8");
                JSONObject json = JaxbUtil.xmlToJson(body);
                json = json.getJSONObject("xml");
                if ("SUCCESS".equalsIgnoreCase(json.getString("return_code"))) {
                    if ("FAIL".equalsIgnoreCase(json.getString("result_code"))) {
                        remoteResponse.setErrorCode(json.getString("err_code"));
                        remoteResponse.setErrorMsg(json.getString("err_code_des"));
                        isSuccess = false;
                    }
                } else {
                    remoteResponse.setErrorCode(json.getString("return_code"));
                    remoteResponse.setErrorMsg(json.getString("return_msg"));
                    isSuccess = false;
                }
                remoteResponse.setBody(json.toJSONString());
            }
            //修改业务状态为失败
            remoteResponse.setSuccessful(isSuccess);
            remoteResponse.setMessage(statusLine.getReasonPhrase());
            getHeaders(remoteResponse, response);
        } catch (Exception e) {
            throw new RuntimeException(e);
        } finally {
            request.releaseConnection();
        }
        return remoteResponse;
    }

    private static void getHeaders(RemoteResponse remoteResponse, CloseableHttpResponse response) {
        Header[] allHeaders = response.getAllHeaders();
        Map<String, String> headers = new HashMap<>();
        for (Header header : allHeaders) {
            headers.put(header.getName(), header.getValue());
        }
        remoteResponse.setHeaders(headers);
    }

    /**
     * 公众号或小程序服务端调用
     *
     * @author 长沙商脉科技有限公司
     * @date 2020/12/11 20:15
     */
    public static RemoteResponse weChatHttpRequest(HttpRequestBase request) {
        RemoteResponse response = NetUtil.doRequest(request);
        if (response.isSuccessful()) {
            JSONObject json = JsonUtil.parse(response.getBody(), JSONObject.class);
            if (json != null) {
                String errorCode = json.getString("errcode");
                if (StringUtils.isNotEmpty(errorCode)) {
                    int code = Integer.parseInt(errorCode);
                    if (code != 0) {
                        response.setErrorCode(errorCode);
                        response.setErrorMsg(json.getString("errmsg"));
                        //修改业务状态为失败
                        response.setSuccessful(false);
                    }
                }
            }
        }
        return response;
    }
}
